package com.ztr.conversion.word2html;

import com.aspose.words.SaveFormat;
import com.ztr.conversion.config.Constants;
import com.ztr.conversion.util.MyFileUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.converter.PicturesManager;
import org.apache.poi.hwpf.converter.WordToHtmlConverter;
import org.apache.poi.hwpf.usermodel.Picture;
import org.apache.poi.hwpf.usermodel.PictureType;
import org.apache.poi.xwpf.converter.core.FileImageExtractor;
import org.apache.poi.xwpf.converter.core.IURIResolver;
import org.apache.poi.xwpf.converter.xhtml.XHTMLConverter;
import org.apache.poi.xwpf.converter.xhtml.XHTMLOptions;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.util.CollectionUtils;
import org.w3c.dom.Document;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.util.List;
import java.util.UUID;

/**
 * <p>
 * Word 转 Html 工具类
 * </p>
 */
@Slf4j
public class Word2HtmlUtil {


    /**
     * 将Word文档的字节内容转换为HTML格式的字节内容。
     * 使用Aspose Words库将Word文档转换为HTML格式，并将转换后的HTML内容存储为临时文件，
     * 然后读取该临时文件的内容作为字节数组返回。
     *
     * @param wordBytes Word文档的字节内容。
     * @return HTML文档的字节内容。
     */
    @SneakyThrows(Exception.class)
    public static byte[] wordBytes2HtmlBytes(byte[] wordBytes) {
        // 生成一个唯一的临时文件路径来存储转换后的HTML文件
        // 创建临时word转html后生成的html文件
        String tmpHtmlFilePath =
                Constants.DEFAULT_FOLDER_TMP_GENERATE + "/" + System.currentTimeMillis() + "-" + getUUID32() + ".html";

        // 使用Aspose Words的Document类从字节流加载Word文档
        com.aspose.words.Document doc = new com.aspose.words.Document(new ByteArrayInputStream(wordBytes));
        // 将加载的Word文档保存为HTML格式到指定的临时文件路径
        doc.save(tmpHtmlFilePath, SaveFormat.HTML);

        // 读取临时HTML文件的内容到字节数组
        byte[] htmlBytes = MyFileUtil.readBytes(tmpHtmlFilePath);

        // 删除不再需要的临时HTML文件
        // 删除临时word文件
        MyFileUtil.deleteFileOrFolder(tmpHtmlFilePath);

        return htmlBytes;
    }


    /**
     * Converts Word document bytes to an HTML file.
     * This method uses Aspose.Words library to handle the conversion, which avoids the need for Microsoft Word to be installed.
     * It directly loads the Word document from the provided byte array and saves it as an HTML file.
     *
     * @param wordBytes    The byte array representation of the Word document.
     * @param htmlFilePath The path where the generated HTML file will be saved.
     * @return A File object pointing to the newly created HTML file.
     * @throws Exception If any error occurs during the document loading or saving process.
     */
    @SneakyThrows(Exception.class)
    public static File wordBytes2HtmlFile(byte[] wordBytes, String htmlFilePath) {
        // Load the Word document from the byte array using Aspose.Words.
        // Load word document from disk.
        com.aspose.words.Document doc = new com.aspose.words.Document(new ByteArrayInputStream(wordBytes));

        // Save the document as an HTML file at the specified path.
        // Save the document into MHTML.
        doc.save(htmlFilePath, SaveFormat.HTML);

        // Return the File object for the newly created HTML file.
        return new File(htmlFilePath);
    }


    /**
     * 生成一个32位的UUID字符串。
     * <p>
     * UUID（Universally Unique Identifier）是一个128位的全局唯一标识符，用于识别互联网上的实体。
     * 这里通过调用UUID.randomUUID()生成一个随机的UUID，然后通过字符串替换去掉其中的连字符("-")，
     * 最后将字符串转换为小写，以满足特定格式的要求。
     *
     * @return 一个32位的UUID字符串，不包含连字符，并且全部为小写字母。
     */
    private static String getUUID32() {
        // 生成一个随机的UUID并将其转换为字符串
        return UUID.randomUUID().toString().replace("-", "").toLowerCase();
    }


    // ================================= ↓↓↓↓↓↓ 【 注：下面方式会丢失一定格式 】 ↓↓↓↓↓↓ ==================================


    /**
     * 将Word文档转换为HTML字符串。
     * 支持.doc和.docx格式的Word文档。转换过程中，图片会被保存到指定的路径，并在HTML中以链接的形式引用。
     *
     * @param fileRootPath 文件根路径，用于拼接Word文件路径和图片保存路径。
     * @param wordFileName Word文件名，包括文件后缀。
     * @param imagePath    图片保存路径，转换后的HTML将引用此路径下的图片。
     * @return 转换后的HTML字符串。
     */
    @SneakyThrows(Exception.class)
    public static String word2Html(String fileRootPath, String wordFileName, String imagePath) {
        // 拼接Word文件的完整路径
        // word 文件路径
        final String wordFilePath = fileRootPath + "/" + wordFileName;
        // 提取Word文件的后缀名
        // 文件后缀名
        final String wordFileNameSuffix = wordFileName.substring(wordFileName.lastIndexOf(".") + 1);

        // 记录日志，显示Word文件的路径
        log.debug("《word转html》 word文件路径:【{}】", wordFilePath);

        // 判断Word文件的格式是否为.docx
        // 判断是否为`docx`文件
        boolean ifDocxSuffix = false;
        if ("docx".equals(wordFileNameSuffix)) {
            ifDocxSuffix = true;
        }

        // 准备输出流，用于存储转换后的HTML字符串
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        if (ifDocxSuffix) {
            // 处理.docx格式的Word文档
            /**
             * word2007和word2003的构建方式不同， 前者的构建方式是xml，后者的构建方式是dom树。 文件的后缀也不同，前者后缀为.docx，后者后缀为.doc 相应的，apache.poi提供了不同的实现类。
             */
            // 加载.docx文件到XWPFDocument对象中
            InputStream inputStream = new FileInputStream(new File(wordFilePath));
            XWPFDocument document = new XWPFDocument(inputStream);
            // 配置HTML转换选项
            XHTMLOptions options = XHTMLOptions.create();
            // 设置图片保存路径
            options.setExtractor(new FileImageExtractor(new File(imagePath)));
            options.setIgnoreStylesIfUnused(false);
            options.setFragment(true);
            // 自定义图片链接的解析器
            options.URIResolver(new IURIResolver() {
                public String resolve(String uri) {
                    // 构建图片链接
                    return imagePath + "/" + uri;
                }
            });
            // 转换XWPFDocument为HTML，输出到out流中
            XHTMLConverter.getInstance().convert(document, out, options);
        } else {
            // 处理.doc格式的Word文档
            HWPFDocument wordDocument = new HWPFDocument(new FileInputStream(wordFilePath));
            WordToHtmlConverter wordToHtmlConverter =
                    new WordToHtmlConverter(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());

            // 设置图片保存策略
            wordToHtmlConverter.setPicturesManager(new PicturesManager() {
                @SneakyThrows(Exception.class)
                public String savePicture(byte[] content, PictureType pictureType, String suggestedName,
                                          float widthInches, float heightInches) {
                    // 仅处理可识别的图片类型
                    if (pictureType.equals(PictureType.UNKNOWN)) {
                        return "";
                    }
                    // 构建图片保存路径并保存图片
                    String htmlImgPath = imagePath + "/" + suggestedName;
                    FileOutputStream os = new FileOutputStream(MyFileUtil.touch(htmlImgPath));
                    os.write(content);
                    os.close();
                    log.debug("图片地址：【{}】", htmlImgPath);
                    return htmlImgPath;
                }
            });

            // 转换Word文档为HTML
            wordToHtmlConverter.processDocument(wordDocument);
            // 保存文档中的图片
            List<Picture> picList = wordDocument.getPicturesTable().getAllPictures();
            if (!CollectionUtils.isEmpty(picList)) {
                picList.forEach(pic -> {
                    // 图片保存逻辑已提前在PicturesManager中实现
                });
            }

            // 获取转换后的HTML文档对象，并将其转换为HTML字符串
            Document htmlDocument = wordToHtmlConverter.getDocument();
            DOMSource domSource = new DOMSource(htmlDocument);
            StreamResult streamResult = new StreamResult(out);

            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer serializer = tf.newTransformer();
            serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
            serializer.setOutputProperty(OutputKeys.INDENT, "yes");
            serializer.setOutputProperty(OutputKeys.METHOD, "html");
            serializer.transform(domSource, streamResult);
        }

        // 关闭输出流
        // 关闭流
        out.close();

        // 将输出流中的内容转换为字符串并返回
        // 返回html文件内容
        return new String(out.toByteArray());
    }


    /**
     * 将Word文档转换为HTML文件。
     * <p>
     * 此方法接收Word文档的根路径、Word文件名和目标HTML文件名作为参数，
     * 并通过调用Word2HtmlUtil将Word内容转换为HTML格式，
     * 最后将转换后的HTML内容写入到指定路径的HTML文件中。
     *
     * @param fileRootPath Word文档和生成的HTML文件的根路径。
     * @param wordFileName Word文档的文件名。
     * @param htmlFileName 生成的HTML文件的文件名。
     * @return 返回生成的HTML文件对象。
     */
    public static File word2HtmlFile(String fileRootPath, String wordFileName, String htmlFileName) {
        // 构建HTML文件的完整路径
        final String htmlFilePath = fileRootPath + "/" + htmlFileName;
        // 调用Word2HtmlUtil将Word文档转换为HTML内容
        // 获取word转html文件内容
        String htmlContent = Word2HtmlUtil.word2HtmlContent(fileRootPath, wordFileName, htmlFileName);
        // 将HTML内容写入到指定路径的文件中
        // 生成html文件
        File htmlFile = MyFileUtil.writeFileContent(htmlContent, htmlFilePath);
        // 记录转换成功的日志信息
        log.debug("word转html成功!  生成html文件路径:【{}】", htmlFilePath);
        return htmlFile;
    }


    /**
     * 将Word文档转换为HTML格式的内容，并保存图片到指定目录。
     * <p>
     * 此方法封装了Word转HTML的流程，包括处理Word中的图片，将图片保存到指定的目录下。
     * 转换后的HTML内容中，图片的路径会被相应地设置为相对路径，以便在HTML文件被打开时能够正确显示图片。
     *
     * @param fileRootPath 文件根路径，用于保存转换后的HTML文件以及Word文档中的图片。
     * @param wordFileName Word文档的文件名，包括文件扩展名。
     * @param htmlFileName 转换后HTML文件的文件名，包括文件扩展名。
     * @return 转换后的HTML内容。
     */
    public static String word2HtmlContent(String fileRootPath, String wordFileName, String htmlFileName) {
        // 定义图片保存路径，相对于文件根路径。
        final String imagePath = fileRootPath + "/image";
        // 定义HTML文件保存路径，相对于文件根路径。
        final String htmlFilePath = fileRootPath + "/" + htmlFileName;

        // 调用Word2HtmlUtil工具类，将Word文档转换为HTML内容。图片会被保存到指定的image路径下。
        // 返回word转html文件内容
        String htmlContent = Word2HtmlUtil.word2Html(fileRootPath, wordFileName, imagePath);

        // 注释掉的代码是用于删除临时图片文件夹的。在某些情况下，可能需要保留这些图片，因此这里未执行删除操作。
        // 是否将本地临时存放图片删除 ？？？
        // MyFileUtil.deleteFileOrFolder(imagePath);

        // 返回转换后的HTML内容。
        return htmlContent;
    }


}
